﻿// Copyright 2007-2009 Stuart Caborn, Alex Scordellis
//  
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not
//  use this file except in compliance with the License. You may obtain a copy of
//  the License at
//  
//  http://www.apache.org/licenses/LICENSE-2.0
//  
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
//  License for the specific language governing permissions and limitations under
//  the License.
// 


using System;
using System.Collections.Generic;
using System.Linq;

namespace NSynthesis.Reflection
{
    public static class ProxySanitizer
    {
        private static IEnumerable<String> InfrastructuralInterfaces
        {
            get
            {
                yield return "Rhino.Mocks.Interfaces.IMockedObject";
                yield return "Castle.Core.Interceptor.IProxyTargetAccessor";
                yield return "System.Runtime.Serialization.ISerializable";
            }
        }

        /// <summary>
        /// If a type is a dynamic proxy, returns the type which was proxied. If not, returns the original type.
        /// </summary>
        public static Type RemoveProxy(this Type typeWhichMayBeDynamicProxy)
        {
            if (typeWhichMayBeDynamicProxy.Assembly.FullName == "DynamicProxyGenAssembly2, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")
            {
                if (typeWhichMayBeDynamicProxy.BaseType == typeof (Object))
                {
                    // This is a mock of an interface so find the interface that is from the app under test, rather than the ones
                    // that are part of the mocking infrastructure.
                    var applicationInterfaces = (from iface in typeWhichMayBeDynamicProxy.GetInterfaces()
                                                where !InfrastructuralInterfaces.Contains(iface.FullName)
                                                select iface).ToList();

                    applicationInterfaces.RemoveAll(type => applicationInterfaces.Any(
                            type1 => type != type1 && type1.GetInterfaces().Contains(type)));

                    if (applicationInterfaces.Count() != 1)
                    {
                        throw new InvalidOperationException("Expected that a Rhino.Mocks interception would have only one application interface.");
                    }
                    return applicationInterfaces.First();
                }

                // This is a mock of a class (abstract or concrete)
                return typeWhichMayBeDynamicProxy.BaseType;
            }
            return typeWhichMayBeDynamicProxy;
        }
    }
}